home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / maestro / source / displytl / xvimage.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-15  |  33.2 KB  |  1,054 lines

  1. /*
  2.  * xv.c - main section of xv.  X setup, window creation, event loop, etc.
  3.  *
  4.  *  Author:    John Bradley, University of Pennsylvania
  5.  *                (bradley@cis.upenn.edu)
  6.  */
  7.  
  8.  
  9. /*
  10.  * Copyright 1989, 1990 by the University of Pennsylvania
  11.  *
  12.  * Permission to use, copy, and distribute for non-commercial purposes,
  13.  * is hereby granted without fee, providing that the above copyright
  14.  * notice appear in all copies and that both the copyright notice and this
  15.  * permission notice appear in supporting documentation. 
  16.  *
  17.  * The software may be modified for your own purposes, but modified versions
  18.  * may not be distributed.
  19.  *
  20.  * This software is provided "as is" without any express or implied warranty.
  21.  */
  22. /* $Header $ */
  23. /* $Log $ */
  24. static char xvtiffrcsid[] = "$Header: /Source/Media/collab/DisplayTool/RCS/xvimage.c,v 1.3 92/10/30 18:49:18 drapeau Exp $";
  25.  
  26. #define NEEDSDIR     /* for value of MAXPATHLEN */
  27. #include "xvimage.h"
  28. #include <X11/Xatom.h>
  29. #include "DisplayTool.h"
  30.  
  31. /* file types that can be read */
  32. #define UNKNOWN  0
  33. #define GIF      1
  34. #define PM       2
  35. #define PBM      3
  36. #define XBM      4
  37. #define SUNRAS   5
  38. #define JFIF     6
  39. #define TIFF     7
  40. #define PDSVICAR 8
  41.  
  42. static unsigned long rootbg, rootfg;  /* fg/bg for root border */
  43. static int    roottile = 0;     /* resize pic to tile evenly on rootW */
  44. static int    automax  = 0;     /* resize pic to dispWIDE, dispHIGH on open */
  45. static int    autoquit = 0;     /* quit after loading first pic to rootW */
  46. static int    autogamma = 1;    /* perform gamma correction by default */
  47. static char  *maingeom = NULL;
  48. static char   initpath[MAXPATHLEN];
  49. XImage        *theImage;     /* X version of epic */
  50.  
  51.  
  52. /* function pre-definitions */
  53. IMAGE openPic(int filenum);
  54. static void    FixAspect();
  55. XImage*        CreateXImage(byte* origData, int width, int height);
  56.  
  57.  
  58. /*******************************************/
  59. IMAGE xvimage_main(char *file)
  60. /*******************************************/
  61. {
  62.   int  imap, ctrlmap, gmap, clrroot;
  63.   char *display, *fname, *whitestr, *blackstr, 
  64.        *fgstr, *bgstr;
  65.   char *rootfgstr, *rootbgstr;
  66.   char *function;
  67.   char *argument;
  68.   XColor ecdef;
  69.   
  70.   getwd(initpath);
  71.   function = "-geom";
  72.   argument = "100x100";
  73.   display = fname = whitestr = blackstr = NULL;                /* init internal variables */
  74.   fgstr = bgstr = rootfgstr = rootbgstr = NULL;
  75.   pic = epic = cpic = NULL;
  76.   theImage = NULL;
  77.   LocalCmap = 0;
  78.   cmd = (char *)strdup("xvimage");
  79.   formatStr[0] ='\0';
  80.  
  81.   expand = 1;  ncols = -1;  noglob = 0;  revvideo = 0;  mono = 0;   /* Init command-line options flags */
  82.   perfect = 0;  ninstall = 0;  fixedaspect = 0;  
  83.   DEBUG = 0;  bwidth = 2;
  84.   useroot = clrroot = noqcheck = rwcolor = fishrunning = 0;
  85.   fish = 0;
  86.   brokeFreeCols = 1;
  87.   defaspect = normaspect = 1.0;
  88.  
  89.   mainW = NULL;
  90.   imap = ctrlmap = gmap = 0;
  91.  
  92.   if (!file)
  93.     {
  94.       printf("NULL filename\n");
  95.       return((IMAGE)NULL);
  96.     }
  97.   namelist[0] = (char *)strdup(file);
  98.   numnames = 1;
  99.   
  100.   if (function)
  101.     {
  102.       if (!strncmp(function,"-as",3)) { /* default aspect */
  103.     int n,d;
  104.     if (sscanf(argument,"%d:%d",&n,&d)!=2 || n<1 || d<1)
  105.       fprintf(stderr,"%s: bad aspect ratio '%s'\n",cmd,argument);
  106.     else defaspect = (float) n / (float) d;
  107.       }
  108.       
  109.       else if (!strncmp(function,"-au",3))  /* autogamma */
  110.     autogamma++;
  111.       
  112.       else if (!strncmp(function,"-ge",3))    /* geometry */
  113.     { 
  114.       maingeom = argument; 
  115.       if (!strcmp(argument, "100x100"))
  116.         fixedaspect++;
  117.     }
  118.     }
  119.   
  120.   if (DEBUG) XSynchronize(theDisp, True);
  121.   
  122.   /* if using root, generally gotta map ctrl window, 'cause there won't be
  123.      any way to ask for it.  (no kbd or mouse events from rootW) */
  124.   if (useroot && !autoquit) 
  125.     ctrlmap = 1;    
  126.   
  127.   ncells    = DisplayCells(theDisp, theScreen);
  128.  
  129.   /* set up white,black colors */
  130.   white = WhitePixel(theDisp,theScreen);
  131.   black = BlackPixel(theDisp,theScreen);
  132.   if (whitestr && XParseColor(theDisp, theCmap, whitestr, &ecdef) &&
  133.       XAllocColor(theDisp, theCmap, &ecdef))  white = ecdef.pixel;
  134.   if (blackstr && XParseColor(theDisp, theCmap, blackstr, &ecdef) &&
  135.       XAllocColor(theDisp, theCmap, &ecdef))  black = ecdef.pixel;
  136.  
  137.   /* set up fg,bg colors */
  138.   fg = black;   bg = white;
  139.   if (fgstr && XParseColor(theDisp, theCmap, fgstr, &ecdef) &&
  140.       XAllocColor(theDisp, theCmap, &ecdef))  fg = ecdef.pixel;
  141.   if (bgstr && XParseColor(theDisp, theCmap, bgstr, &ecdef) &&
  142.       XAllocColor(theDisp, theCmap, &ecdef))  bg = ecdef.pixel;
  143.  
  144.   /* set up root fg,bg colors */
  145.   rootfg = white;   rootbg = black;
  146.   if (rootfgstr && XParseColor(theDisp, theCmap, rootfgstr, &ecdef) &&
  147.       XAllocColor(theDisp, theCmap, &ecdef))  rootfg = ecdef.pixel;
  148.   if (rootbgstr && XParseColor(theDisp, theCmap, rootbgstr, &ecdef) &&
  149.       XAllocColor(theDisp, theCmap, &ecdef))  rootbg = ecdef.pixel;
  150.  
  151.   XSetForeground(theDisp,theGC,fg);
  152.   XSetBackground(theDisp,theGC,bg);
  153.  
  154.   /* set up infofg,infobg colors */
  155.   infofg = fg;   infobg = bg;
  156.  
  157.  
  158.   /* if '-mono' not forced, determine if we're on a b/w or color monitor */
  159.   if (!mono) {
  160.     if (DEBUG) fprintf(stderr,"%s: VisualClass = %d\n",cmd, theVisual->class);
  161.     if (theVisual->class == StaticGray || theVisual->class == GrayScale)
  162.       mono = 1;
  163.   }
  164.  
  165.   /* if ncols wasn't set, set it to 2^dispDEEP, unless dispDEEP=1, in which
  166.      case ncols = 0;  (ncols = max number of colors allocated.  on 1-bit
  167.      displays, no colors are allocated */
  168.  
  169.   if (ncols == -1)
  170.   {
  171.     if (dispDEEP>1) ncols = 1<<dispDEEP;
  172.     else ncols = 0;
  173.   }
  174.   else if (ncols>256)                            /* So program doesn't blow up */
  175.     ncols = 256;
  176.  
  177.   if (numnames==0)                            /* No filenames.  build one-name (stdio) list */
  178.   {
  179.     namelist[0] = "<stdin>";
  180.     numnames = 1;
  181.   }
  182.  
  183.   if (!(theVisual->class & 1) && rwcolor)                /* If we're not on a colormapped display, turn off rwcolor */
  184.   {
  185.     fprintf(stderr,"xv: not a colormapped display.  'rwcolor' turned off.\n");
  186.     rwcolor = 0;
  187.   }
  188.   return(openPic(0));
  189. }                                    /* end function xvimage_main */
  190.  
  191.  
  192.  
  193. /***********************************/
  194. IMAGE openPic(int filenum)
  195. {
  196.   /* tries to load file #filenum (from 'namelist' list)
  197.    * returns 0 on failure (cleans up after itself)
  198.    * if successful, returns 1, creates mainW
  199.    */
  200.  
  201.   int   i,filetype,okay,freename, nw, nh;
  202.   char *tmp;
  203.   FILE *fp;
  204.   char *fullname,                            /* full name of the original file */
  205.         filename[256],                            /* full name of the file to be loaded (could be /tmp) */
  206.         basename[128];                            /* just the name of the original file. No path */
  207.   byte magicno[8];                            /* first 8 bytes of file */
  208.   IMAGE        newImage = (IMAGE)NULL;                    /* Holds new IMAGE info if function is successful */
  209.   
  210.   normaspect = defaspect;
  211.   curname = filenum;
  212.   XFlush(theDisp);                            /* update NOW */
  213.   formatStr[0] = '\0';                            /* Clear any old error messages */
  214.   okay = 0;
  215.   fullname = namelist[filenum];                        /* Set up fullname and basename */
  216.   tmp = rindex(fullname,'/');
  217.   if (!tmp) tmp = fullname; else tmp++;
  218.   strcpy(basename,tmp);
  219.   if (strlen(basename)>2 && strcmp(basename+strlen(basename)-2,".Z")==0) 
  220.     basename[strlen(basename)-2]='\0';                    /* chop off .Z, if any */
  221.  
  222.   freename = 0;
  223.   if (fullname[0] != '/' && strcmp(fullname,"<stdin>")!=0)        /* If fullname doesn't start with a '/' (ie, it's... */
  224.   {                                    /* ... a relative path), (and it's not the special... */
  225.     char *tmp;                                /* ...case '<stdin>') prepend 'initpath' to it */
  226.     tmp = (char *) MyMalloc(strlen(fullname) + strlen(initpath) + 2);
  227.     if (!tmp) FatalError("MyMalloc 'filename' failed");
  228.     sprintf(tmp,"%s/%s", initpath, fullname);
  229.     fullname = tmp;
  230.     freename = 1;
  231.   }
  232.   
  233.   strcpy(filename,fullname);
  234.  
  235.   /* now, try to determine what type of file we've got by reading the
  236.      first couple bytes and looking for a Magic Number */
  237.  
  238.   fp=fopen(filename,"r");
  239.   if (!fp) {
  240.     goto FAILED;
  241.   }
  242.  
  243.   fread(magicno,8,1,fp);  
  244.   fclose(fp);
  245.   filetype = UNKNOWN;
  246.   if (strncmp((char *) magicno,"GIF87a",6)==0 ||
  247.       strncmp((char *) magicno,"GIF89a",6)==0) filetype = GIF;
  248.   
  249.   else if (strncmp((char *) magicno,"VIEW",4)==0 ||
  250.        strncmp((char *) magicno,"WEIV",4)==0) filetype = PM;
  251.   
  252.   else if (magicno[0] == 'P' && magicno[1]>='1' && 
  253.        magicno[1]<='6') filetype = PBM;
  254.   
  255.   else if (strncmp((char *) magicno,"#define",7)==0) filetype = XBM;
  256.   
  257.   else if (magicno[0]==0x59 && (magicno[1]&0x7f)==0x26 &&
  258.        magicno[2]==0x6a && (magicno[3]&0x7f)==0x15) filetype = SUNRAS;
  259.   
  260.   else if (magicno[0]==0xff && magicno[1]==0xd8 && 
  261.        magicno[2]==0xff) filetype = JFIF;
  262.  
  263.   else if (strncmp(magicno,"MM",2)==0 ||
  264.        strncmp(magicno,"II",2)==0) filetype = TIFF;
  265.  
  266.   else if (strncmp((char *) magicno,  "NJPL1I00",8)==0 || /* fixed-len pds */
  267.        strncmp((char *) magicno+2,"NJPL1I",  6)==0 || /* vger+other pds */
  268.            strncmp((char *) magicno,  "CCSD3ZF", 7)==0 || /* vikng pds browse*/
  269.        strncmp((char *) magicno+2,"CCSD3Z",  6)==0 || /* vik. huffman pds*/
  270.        strncmp((char *) magicno,  "LBLSIZE=",8)==0)   /* vicar */
  271.     filetype = PDSVICAR;
  272.  
  273.   if (filetype == UNKNOWN) {
  274.     goto FAILED;
  275.   }
  276.  
  277.   switch (filetype) {
  278.   case GIF:    i = LoadGIF(filename,ncols);     break;
  279.   case PM:     i = LoadPM (filename,ncols);     break;
  280.   case PBM:    i = LoadPBM(filename,ncols);     break;  
  281.   case XBM:    i = LoadXBM(filename,ncols);     break;
  282.   case SUNRAS: i = LoadSunRas(filename, ncols); break;
  283.   case JFIF:   i = LoadJFIF(filename, ncols);   break;   
  284.   case TIFF:   i = LoadTIFF(filename, ncols);   break;
  285.   case PDSVICAR:  i = LoadPDS(filename, ncols);    break;  
  286.   }
  287.  
  288.   if (i) {
  289.     goto FAILED;
  290.   }
  291. /*
  292.   for (i=0; i<numcols; i++)
  293.     printf("r[%d]=%d g[%d]=%d b[%d]=%d\n", i, r[i], i, g[i], i, b[i]); 
  294. */
  295.  
  296.   /* successfully read this picture */
  297.   if (strcmp(fullname,filename)!=0)                    /* If we read a /tmp file, delete it;  won't be... */
  298.     unlink(filename);                            /* ...needing it any more */
  299.  
  300.   normFact = 1;  nw = pWIDE;  nh = pHIGH;
  301.   /* if pic is larger than screen, half picture until it fits on screen */
  302.   while (nw > dispWIDE || nh > dispHIGH) {
  303.     nw = nw / 2;  
  304.     nh = nh / 2;
  305.     normFact = normFact * 2;
  306.   }
  307.  
  308.   /* expand:  if expansion is negative, treat it as a reciprocal */
  309.   if (expand<0) { eWIDE = pWIDE/abs(expand);  eHIGH = pHIGH/abs(expand); }
  310.            else { eWIDE = pWIDE * expand;     eHIGH = pHIGH * expand; }
  311.  
  312.   if (1) {    /* bry -- was useroot */
  313.     int i,x,y;  unsigned int w,h;
  314.     i = XParseGeometry(maingeom,&x,&y,&w,&h);
  315.     if (i&WidthValue)  eWIDE = w;
  316.     if (i&HeightValue) eHIGH = h;
  317.     RANGE(eWIDE,1,dispWIDE);  RANGE(eHIGH,1,dispHIGH);
  318.  
  319.     if (roottile) {
  320.       /* make picture size a divisor of the rootW size.  round down */
  321.       i = (dispWIDE + eWIDE-1) / eWIDE;   eWIDE = (dispWIDE + i-1) / i;
  322.       i = (dispHIGH + eHIGH-1) / eHIGH;   eHIGH = (dispHIGH + i-1) / i;
  323.     }
  324.   }
  325.  
  326.   cpic = pic;  cWIDE = pWIDE;  cHIGH = pHIGH;  cXOFF = cYOFF = 0;
  327.  
  328.   if (automax) { 
  329.     eWIDE = dispWIDE;  eHIGH = dispHIGH;
  330.     if (fixedaspect) FixAspect(0,&eWIDE,&eHIGH);
  331.   }
  332.  
  333.   if (useroot) {    
  334.     mainW = rootW;
  335.  
  336.     if (theVisual->class & 1)                        /* Clear old root pixmap before doing the ... */
  337.     {                                    /* ...'alloc colors scene' to avoid annoying... */
  338.       XSetWindowBackgroundPixmap(theDisp, rootW, None);            /* ...'rainbow' effect as colors are realloced */
  339.       XClearWindow(theDisp, rootW);
  340.       XFlush(theDisp);
  341.     }
  342.   }
  343.  
  344.   if (fixedaspect) FixAspect(0,&eWIDE,&eHIGH);
  345.   else if (i&WidthValue && i&HeightValue)
  346.     { RANGE(eWIDE,1,dispWIDE);  RANGE(eHIGH,1,dispHIGH); }
  347.  
  348.   SortColormap();
  349.  
  350.   for (i=0; i<numcols; i++)                        /* Save desired RGB colormap (before gamma-correcting it) */
  351.     { rorg[i] = r[i];  gorg[i] = g[i];  borg[i] = b[i]; }
  352.  
  353.   DoMonoAndRV();
  354.   AllocColors();
  355.  
  356.   if (LocalCmap)
  357.   {
  358.     XSetWindowAttributes xswa;
  359.     if (!ninstall) 
  360.       {                                        /* bry - you put in these parens */
  361.     XInstallColormap(theDisp,LocalCmap);
  362.     xswa.colormap = LocalCmap;
  363.     XChangeWindowAttributes(theDisp,mainW,CWColormap,&xswa);
  364.       }
  365.   }
  366.   newImage = (IMAGE)MyMalloc(sizeof(struct ImageStruct));        /* Successful loading of image; create a structure to... */
  367.   if (newImage != (IMAGE)NULL)                        /* ...hold the new information */
  368.   {
  369.     NullFields(newImage);
  370.     newImage->filename = strdup(fullname);
  371.     newImage->format = strdup(formatStr);
  372.     newImage->origWidth = pWIDE;
  373.     newImage->origHeight = pHIGH;
  374.     newImage->galleryImage = (XImage*)NULL;
  375.     newImage->slideImage = (XImage*)NULL;
  376.     newImage->largeImage = (XImage*)NULL;
  377.     newImage->imageData = cpic;
  378.   }
  379.   if (freename) free(fullname);
  380.   return (newImage);
  381.   
  382.  FAILED:
  383.   if (strcmp(fullname,filename)!=0) unlink(filename);            /* kill /tmp file */
  384.   if (freename) free(fullname);
  385.   return ((IMAGE)NULL);
  386. }                                    /* end function openPic */
  387.  
  388.  
  389. /***********************************/
  390. static void FixAspect(grow,w,h)
  391. int   grow;
  392. int   *w, *h;
  393. {
  394.   /* computes new values of eWIDE and eHIGH which will have aspect ratio
  395.      'normaspect'.  If 'grow' it will preserve aspect by enlarging, 
  396.      otherwise, it will shrink to preserve aspect ratio.  
  397.      Returns these values in 'w' and 'h' */
  398.  
  399.   float xr,yr,curaspect,a,exp;
  400.  
  401.   *w = eWIDE;  *h = eHIGH;
  402.  
  403.   /* xr,yr are expansion factors */
  404.   xr = ((float) eWIDE) / cWIDE;
  405.   yr = ((float) eHIGH) / cHIGH;
  406.   curaspect  = xr / yr;
  407.  
  408.   /* if too narrow & shrink, shrink height.  too wide and grow, grow height */
  409.   if ((curaspect < normaspect && !grow) || 
  410.       (curaspect > normaspect &&  grow)) {    /* modify height */
  411.     exp = curaspect / normaspect;
  412.     *h = (int) (eHIGH * exp + .5);
  413.   }
  414.  
  415.   /* if too narrow & grow, grow width.  too wide and shrink, shrink width */
  416.   if ((curaspect < normaspect &&  grow) || 
  417.       (curaspect > normaspect && !grow)) {    /* modify width */
  418.     exp = normaspect / curaspect;
  419.     *w = (int) (eWIDE * exp + .5);
  420.   }
  421.  
  422.  
  423.   /* shrink to fit screen without changing aspect ratio */
  424.   if (*w>dispWIDE) {
  425.     int i;
  426.     a = (float) *w / dispWIDE;
  427.     *w = dispWIDE;
  428.     i = (int) (*h / a + .5);        /* avoid freaking some optimizers */
  429.     *h = i;
  430.   }
  431.  
  432.   if (*h>dispHIGH) {
  433.     a = (float) *h / dispHIGH;
  434.     *h = dispHIGH;
  435.     *w = (int) (*w / a + .5);
  436.   }
  437.  
  438.   if (*w < 1) *w = 1;
  439.   if (*h < 1) *h = 1;
  440. }
  441.  
  442.  
  443. /***********************************/
  444.  
  445. XImage* Resize(byte*    origData,
  446.            int    origWidth, int origHeight,
  447.            int    newWidth, int newHeight)
  448. {
  449.   int        cy,ex,ey, *cxarrp;
  450.   int        newSize;
  451.   byte        *clptr,*elptr,*epptr;
  452.   static int    oldCxArrSize = 0;
  453.   static int    sizeOfOldImageData = 0;
  454.   static int*    cxarr = (int*)NULL;
  455.   static byte*    newImageData = (byte*)NULL;
  456.   XImage*    newXImage = (XImage*)NULL;
  457.   char        diagString[MAXPATHLEN];
  458.   
  459.   clptr = NULL;  cxarrp = NULL;  cy = 0;                /* Shut up compiler */
  460.   RANGE(newWidth,1,dispWIDE);  RANGE(newHeight,1,dispHIGH);        /* Force newWidth, newHeight into valid ranges */
  461.   if (DEBUG) fprintf(stderr,"%s: Resize(%d,%d)  new size=%d,%d  original size=%d,%d\n",
  462.              cmd, newWidth, newHeight, eWIDE,eHIGH,cWIDE,cHIGH);
  463.   
  464.   newSize = newWidth * newHeight;                    /* Calculate size in bytes of new image */
  465.   if (sizeOfOldImageData < newSize)                    /* Is it necessary to re-allocate space? */
  466.   {                                    /* Yes, free up old space, allocate a larger block */
  467.     if (newImageData != (byte*)NULL)                    /* Free up old space, if necessary */
  468.       free(newImageData);
  469.     newImageData = (byte *) MyMalloc(newSize);                /* Create a new image of the appropriate size */
  470.     if (newImageData == (byte*)NULL)                    /* Did the allocation fail? */
  471.     {                                    /* Yes, report the error. */
  472.       sprintf(str,"unable to MyMalloc a %dx%d image\n",
  473.           newWidth, newHeight);
  474.       FatalError(str);
  475.       return(XImage*)NULL;
  476.     }
  477.     sizeOfOldImageData = newSize;                    /* Update size of memory allocated for new image data */
  478.   }
  479.   /* the scaling routine.  not really all that scary after all... */
  480.   
  481.   /* OPTIMIZATON IDEA.  MyMalloc an eWIDE array of ints which will hold the
  482.      values of the equation px = (pWIDE * ex) / eWIDE.  Faster than doing 
  483.      a mul and a div for every point in picture */
  484.   
  485.   if ((cxarr == (int*)NULL) ||                        /* Is it necessary to re-allocate space? */
  486.       (oldCxArrSize < newWidth * sizeof(int)))
  487.   {                                    /* Yes, free up old space, allocate a larger block */
  488.     sprintf(diagString, "In Resize, must allocate a cxarr of %d bytes (oldCxArrSize is %d).\n",
  489.         newWidth * sizeof(int), oldCxArrSize);
  490.     PrintDTDiagnostics(diagString);
  491.     if (cxarr != (int*)NULL)                        /* Free up old space, if necessary */
  492.       free(cxarr);
  493.     cxarr = (int*) MyMalloc(newWidth * sizeof(int));            /* Create a new cxarr of the appropriate size */
  494.     if (cxarr == (int*)NULL)                        /* Did the allocation fail? */
  495.     {                                    /* Yes, report the error. */
  496.       sprintf(str,"unable to MyMalloc one cxarr line of size %d.\n",
  497.           newWidth * sizeof(int));
  498.       FatalError(str);
  499.       return(XImage*)NULL;
  500.     }
  501.     oldCxArrSize = newWidth * sizeof(int);                /* Update size of memory allocated for one line of image */
  502.   }
  503.   for (ex=0; ex < newWidth; ex++)
  504.     cxarr[ex] = (origWidth * ex) / newWidth;
  505.   
  506.   elptr = epptr = newImageData;
  507.   for (ey=0;  ey < newHeight;  ey++, elptr+=newWidth)
  508.   {
  509.     cy = (origHeight * ey) / newHeight;
  510.     epptr = elptr;
  511.     clptr = origData + (cy * origWidth);
  512.     for (ex=0, cxarrp = cxarr;  ex < newWidth;  ex++, epptr++) 
  513.       *epptr = clptr[*cxarrp++];
  514.   }
  515.   newXImage = CreateXImage(newImageData, newWidth, newHeight);        /* Now make something displayable out of newImageData */
  516.   return(newXImage);
  517. }                                    /* end function Resize */
  518.  
  519.  
  520.  
  521. /************************************************/
  522. /* structure and routine used in SortColormap() */
  523. /************************************************/
  524.  
  525. typedef struct thing 
  526.     { byte r,g,b; 
  527.       int oldindex; 
  528.       int use; } CMAPENT;
  529.  
  530.  
  531. static int CMAPcompare(a,b)
  532. CMAPENT *a,*b;
  533. {
  534.   return (b->use - a->use);
  535. }
  536.  
  537.  
  538. /***********************************/
  539. void SortColormap()
  540. {
  541.   byte *p;
  542.   int   i, j, k, mdist, entry, mn, d, hist[256], trans[256];
  543.   static CMAPENT c[256], c1[256], *cp, *cj, *ck;
  544.  
  545.  
  546.   /* no point doing this if we're on a 1-bit display */
  547.   if (ncols == 0) { numcols = 256; return; }
  548.   
  549.   /* initialize histogram and compute it */
  550.   for (i=0; i<256; i++) hist[i]=0;
  551.   for (i=pWIDE*pHIGH, p=pic; i; i--, p++) hist[*p]++;
  552.   
  553.   if (DEBUG>1) {
  554.     fprintf(stderr,"%s: Desired colormap\n",cmd);
  555.     for (i=0; i<256; i++) 
  556.       if (hist[i]) fprintf(stderr,"(%3d  %02x,%02x,%02x)     ",
  557.                i,r[i],g[i],b[i]);
  558.     fprintf(stderr,"\n\n");
  559.   }
  560.   
  561.   
  562.   /* put the actually-used colors into the 'c' array in the order they occur */
  563.   /* also, while we're at it, calculate numcols */
  564.   for (i=numcols=0; i<256; i++) {
  565.     if (hist[i]) { 
  566.       cp = &c[numcols++];
  567.       cp->r = r[i];  cp->g = g[i];  cp->b = b[i];
  568.       cp->use = hist[i];  cp->oldindex = i;
  569.     }
  570.   }
  571.  
  572.  
  573.   /* find most-used color, put that in c1[0] */
  574.   entry = -1;  mdist = -1;
  575.   for (i=0; i<numcols; i++) {
  576.     if (c[i].use > mdist) { mdist = c[i].use;  entry=i; }
  577.   }
  578.   memcpy(&c1[0], &c[entry], sizeof(CMAPENT));
  579.   c[entry].use = 0;   /* and mark it dealt with */
  580.   
  581.   
  582.   /* sort rest of colormap, in order of decreasing 'distance' from already
  583.      allocated elements.
  584.   
  585.      FURTHER MODIFICATION of algorithm.  The algorithm's performance
  586.      utterly goes to hell as numcols increases.  (Probably on the order
  587.      of O^3 performance).  Since I don't see a clever way of rewriting
  588.      the algorithm for O^2 performance (which'd be acceptable), I'm going
  589.      to make a trade-off.  I'll only run the algorithm for the first 32 colors
  590.      (or so).  It can do that Real Fast.  Then I'll just stick the rest of
  591.      the unsorted colors (if any), and tack them on the end, in order of
  592.      amount of use.  This should give similar picture quality, with 
  593.      much higher performance. */
  594.  
  595.   for (i=1; i<numcols && i<32; i++) {
  596.     /* find the i'th most different color */
  597.     entry = -1;  mdist = -1;
  598.     for (j=0, cj=c; j<numcols; j++,cj++) {
  599.       if (cj->use) {  /* this color has not been marked already */
  600.     mn = 10000;
  601.     for (k=0, ck=c1; k<i; k++,ck++) {
  602.       d = abs(cj->r - ck->r) + abs(cj->g - ck->g) + abs(cj->b - ck->b);
  603.       if (mn>d) mn=d;
  604.     }
  605.     /* mn = minimum distance from c[j] to already used colors */
  606.     /* we want to select the unused color that has the greatest mn */
  607.     if (mn > mdist) { mdist = mn;  entry = j; }
  608.       }
  609.     }
  610.     
  611.     /* c[entry] is the next color to put in the map.  do so */
  612.     memcpy(&c1[i], &c[entry], sizeof(CMAPENT));
  613.     c[entry].use = 0;
  614.   }
  615.   
  616.   /* tack rest of colors onto colormap in decreasing order of use */
  617.   qsort((char *) c,numcols,sizeof(CMAPENT),CMAPcompare);
  618.   memcpy(&c1[i], c, (numcols - i) * sizeof(CMAPENT));
  619.  
  620.  
  621.   /* build translation table */
  622.   for (i=0; i<numcols; i++) trans[ c1[i].oldindex ] = i;
  623.   
  624.   /* modify 'pic' to reflect the new colormap */
  625.   for (i=pWIDE*pHIGH, p=pic; i; i--, p++) { j = trans[*p];  *p = j; }
  626.   
  627.   /* and copy the new colormap into *the* colormap */
  628.   for (i=0; i<numcols; i++) {
  629.     r[i] = c1[i].r;  g[i] = c1[i].g;  b[i] = c1[i].b;
  630.   }
  631.   
  632.   if (DEBUG>1) {
  633.     fprintf(stderr,"%s: result of sorting colormap\n",cmd);
  634.     for (i=0; i<numcols; i++) 
  635.       fprintf(stderr,"(%3d  %02x,%02x,%02x)     ",i,r[i],g[i],b[i]);
  636.     fprintf(stderr,"\n\n");
  637.     
  638.     fprintf(stderr,"%s: translate table\n",cmd);
  639.     for (i=0; i<numcols; i++) 
  640.       fprintf(stderr,"%3d->%3d  ",i,trans[i]);
  641.     fprintf(stderr,"\n\n");
  642.   }
  643.   
  644. }
  645.  
  646. #define NOPIX 0xffffffff    
  647.  
  648. /***********************************/
  649. void AllocColors()
  650. {
  651.   int      i, j, unique, p2alloc, p3alloc;
  652.   Colormap cmap;
  653.   XColor   defs[256];
  654.   XColor   ctab[256];
  655.   int      dc;
  656.  
  657.   nfcols = unique = p2alloc = p3alloc = 0;
  658.   rwthistime = 0;
  659.  
  660.  
  661.   if (ncols == 0) {
  662.     printf("no colors allocated.  Using black & white.\n");
  663.     return;
  664.   }
  665.  
  666.   /* FIRST PASS COLOR ALLOCATION:  
  667.      for each color in the 'desired colormap', try to get it via
  668.      XAllocColor().  If for any reason it fails, mark that pixel
  669.      'unallocated' and worry about it later.  Repeat. */
  670.  
  671.   /* attempt to allocate first ncols entries in colormap 
  672.      note: On displays with less than 8 bits per RGB gun, it's quite
  673.      possible that different colors in the original picture will be
  674.      mapped to the same color on the screen.  X does this for you
  675.      silently.  However, this is not-desirable for this application, 
  676.      because when I say 'allocate me 32 colors' I want it to allocate
  677.      32 different colors, not 32 instances of the same 4 shades... */
  678.   
  679.   for (i=0; i<numcols; i++) cols[i] = NOPIX;
  680.   
  681.   cmap = theCmap;
  682.   for (i=0; i<numcols && unique<ncols; i++) {
  683. /*    printf("r%ld g%ld b%ld   ", r[i], g[i], b[i]); */
  684.     defs[i].red   = r[i]<<8;
  685.     defs[i].green = g[i]<<8;
  686.     defs[i].blue  = b[i]<<8;
  687.     defs[i].flags = DoRed | DoGreen | DoBlue;
  688.     
  689.     if (XAllocColor(theDisp, cmap, &defs[i])) { 
  690.       unsigned long pixel, *fcptr;
  691.       pixel = cols[i] = defs[i].pixel;
  692.       
  693.       /* see if the newly allocated color is new and different */
  694.       for (j=0, fcptr=freecols; j<nfcols && *fcptr!=pixel; j++,fcptr++);
  695.       if (j==nfcols) unique++;
  696.       
  697.       fc2pcol[nfcols] = i;
  698.       freecols[nfcols++] = pixel;
  699.     }
  700.  
  701.     else {
  702.       /* the allocation failed.  If we want 'perfect' color, and we haven't 
  703.      already created our own colormap, we'll want to do so */
  704.       if (perfect && !LocalCmap) {
  705.     LocalCmap = XCopyColormapAndFree(theDisp,theCmap);
  706.     XSetWindowColormap(theDisp,mainW, LocalCmap);
  707.     cmap = LocalCmap;
  708.     i--;      /* redo the allocation request */
  709.       }
  710.  
  711.       else
  712.     /* either we don't care about perfect color, or we do care, have
  713.        allocated our own colormap, and have STILL run out of colors
  714.        (possible, even on an 8 bit display), just mark pixel as
  715.        unallocated.  We'll deal with it later */
  716.     cols[i] = NOPIX;
  717.     }
  718.   }  /* FIRST PASS */
  719.   
  720.   if (nfcols==numcols && verbose) {
  721.     if (numcols != unique)
  722.       printf("Got all %d desired colors.  (%d unique)\n", numcols,
  723.           unique);
  724.     else
  725.       printf("Got all %d desired colors.\n", numcols);
  726.  
  727.     return;
  728.   }
  729.   
  730.  
  731.  
  732.   /* SECOND PASS COLOR ALLOCATION:
  733.      Allocating 'exact' colors failed.  Now try to allocate 'closest'
  734.      colors.
  735.  
  736.      Read entire X colormap (or first 256 entries) in from display.
  737.      for each unallocated pixel, find the closest color that actually
  738.      is in the X colormap.  Try to allocate that color (read only).
  739.      If that fails, the THIRD PASS will deal with it */
  740.  
  741.   if (verbose)
  742.     printf("Got %d out of %d colors.  (%d unique)\n", 
  743.        nfcols,numcols,unique);
  744.  
  745.   /* read entire colormap (or first 256 entries) into 'ctab' */
  746.   dc = (ncells<256) ? ncells : 256;
  747.   for (i=0; i<dc; i++) ctab[i].pixel = (unsigned long) i;
  748.  
  749.   XQueryColors(theDisp, cmap, ctab, dc);
  750.  
  751.   for (i=0; i<numcols && unique<ncols; i++)
  752.     if (cols[i]==NOPIX) {  /* an unallocated pixel */
  753.       int           d, mdist, close;
  754.       unsigned long ri,gi,bi;
  755.  
  756.       mdist = 100000;   close = -1;
  757.       ri = r[i];  gi = g[i];  bi = b[i];
  758.       
  759.       for (j=0; j<dc; j++) {
  760.     d = abs(ri - (ctab[j].red>>8)) +
  761.         abs(gi - (ctab[j].green>>8)) +
  762.         abs(bi - (ctab[j].blue>>8));
  763.     if (d<mdist) { mdist=d; close=j; }
  764.       }
  765.  
  766.       if (close<0) FatalError("This Can't Happen! (How reassuring.)");
  767.       if (XAllocColor(theDisp, cmap, &ctab[close])) { 
  768.     memcpy(&defs[i], &ctab[close], sizeof(XColor));
  769.     cols[i] = ctab[close].pixel;
  770.     fc2pcol[nfcols] = i;
  771.     freecols[nfcols++] = cols[i];
  772.     p2alloc++;
  773.     unique++;
  774.       }
  775.     }
  776.  
  777.  
  778.   /* THIRD PASS COLOR ALLOCATION:
  779.      We've alloc'ed all the colors we can.  Now, we have to map any
  780.      remaining unalloced pixels into either A) the colors that we DID get
  781.      (noglob), or B) the colors found in the X colormap */
  782.  
  783.   for (i=0; i<numcols; i++) {
  784.     if (cols[i] == NOPIX) {  /* an unallocated pixel */
  785.       int           d, k, mdist, close;
  786.       unsigned long ri,gi,bi;
  787.  
  788.       mdist = 100000;   close = -1;
  789.       ri = r[i];  gi = g[i];  bi = b[i];
  790.       
  791.       if (!noglob) {   /* search the entire X colormap */
  792.     for (j=0; j<dc; j++) {
  793.       d = abs(ri - (ctab[j].red>>8)) +
  794.           abs(gi - (ctab[j].green>>8)) +
  795.           abs(bi - (ctab[j].blue>>8));
  796.       if (d<mdist) { mdist=d; close=j; }
  797.     }
  798.     if (close<0) FatalError("This Can't Happen! (How reassuring.)");
  799.     memcpy(&defs[i], &ctab[close], sizeof(XColor));
  800.     cols[i] = defs[i].pixel;
  801.     p3alloc++;
  802.       }
  803.       
  804.       else {                     /* only search the alloc'd colors */
  805.     for (j=0; j<nfcols; j++) {
  806.       k = fc2pcol[j];
  807.       d = abs(ri - (defs[k].red>>8)) +
  808.           abs(gi - (defs[k].green>>8)) +
  809.           abs(bi - (defs[k].blue>>8));
  810.       if (d<mdist) { mdist=d;  close=k; }
  811.     }
  812.     if (close<0) FatalError("This Can't Happen! (How reassuring.)");
  813.     memcpy(&defs[i], &defs[close], sizeof(XColor));
  814.     cols[i] = defs[i].pixel;
  815.       }
  816.     }
  817.   }  /* THIRD PASS */
  818.  
  819.   if (verbose)
  820.     {
  821.       if (p2alloc && p3alloc)
  822.     printf("Got %d 'close' color%s.  'Borrowed' %d color%s.\n",
  823.            p2alloc, (p2alloc>1) ? "s" : "", 
  824.            p3alloc, (p3alloc>1) ? "s" : "");
  825.       
  826.       else if (p2alloc && !p3alloc) 
  827.     printf("Got %d 'close' color%s.\n",
  828.            p2alloc, (p2alloc>1) ? "s" : "");
  829.       
  830.       else if (!p2alloc && p3alloc) 
  831.     printf("'Borrowed' %d color%s.\n",
  832.            p3alloc, (p3alloc>1) ? "s" : "");
  833.     }
  834. }
  835.  
  836.  
  837. /***********************************/
  838. void DoMonoAndRV()
  839. {
  840.   int i;
  841.  
  842.   /* operate on original colors, before any gamma correction */
  843.   for (i=0; i<numcols; i++) {
  844.     r[i] = rorg[i];  g[i] = gorg[i];  b[i] = borg[i];
  845.   }
  846. }
  847.  
  848.  
  849.  
  850. XImage* CreateXImage(byte* origData, int width, int height)
  851. {
  852.   int        i;
  853.   byte        *ip, *pp;
  854.   static byte*    imagedata = (byte*)NULL;
  855.   byte*        lip;
  856.   int        bperline, half, j;
  857.   
  858.  /*
  859.    * this has to do the tricky bit of converting the data in 'origData'
  860.    * into something usable for X.
  861.    *
  862.    * Algorithm notes:
  863.    *   if dispDEEP is 8, nothing has to be done other than create an
  864.    *      Ximage (ZPixmap, depth=8) and point it at the 'origData' data.
  865.    *
  866.    *   if dispDEEP is 1, format'll be an XYBitmap, special case code
  867.    *   
  868.    *   if dispDEEP is 4, format'll be a ZPixmap, 4 or 8 bits per pixel
  869.    *
  870.    *   if dispDEEP is 6, format'll be a ZPixmap, 8 bits per pixel
  871.    *
  872.    *   if dispDEEP is 24 or 32, format'll be a ZPixmap.  32 bits per pixel
  873.    *
  874.    *   any other value of dispDEEP will use a XYPixmap of the appropriate
  875.    *   depth, and some slug-like general-case code  DOESN'T YET!!
  876.    */
  877.   
  878.   if (DEBUG) 
  879.     fprintf(stderr,"CreateXImage: creating a %dx%d Ximage, %d bits deep\n",
  880.         width, height, dispDEEP);
  881.   if (!origData)
  882.   {
  883.     fprintf(stderr,"CreateXImage called while origData was null.\n");
  884.     return((XImage*)NULL);
  885.   }
  886.   
  887.   switch (dispDEEP) 
  888.   {
  889.    case 8:
  890.     imagedata = (byte *) MyMalloc(width*height);            /* Try to allocate space for the actual X Image data */
  891.     if (imagedata == (byte*)NULL)
  892.     {
  893.       PrintDTDiagnostics("In CreateXImage, could not allocate enough image data.\n");
  894.       return(XImage*)NULL;
  895.     }
  896.     for (i=width*height, pp=origData, ip=imagedata; i>0; i--,pp++,ip++)
  897.     {
  898.       *ip = (byte) cols[*pp];
  899.     }
  900.     
  901.     theImage = XCreateImage(theDisp,theVisual,dispDEEP,ZPixmap,0,
  902.                 (char *) imagedata, width, height, 8, 0);
  903.     if (!theImage) FatalError("couldn't create theImage!");
  904.     break;
  905.     
  906.   /*********************************/
  907.   
  908.    case 1:
  909.     theImage = XCreateImage(theDisp, theVisual, dispDEEP, XYPixmap, 0, NULL, 
  910.                 width, height, 8, 0);
  911.     if (!theImage) FatalError("couldn't create theImage!");
  912.     imagedata = (byte *) MyMalloc(theImage->bytes_per_line * height); /* Try to allocate space for the actual X Image data */
  913.     if (imagedata == (byte*)NULL)
  914.     {
  915.       PrintDTDiagnostics("In CreateXImage, could not allocate enough image data.\n");
  916.       return(XImage*)NULL;
  917.     }
  918.     theImage->data = (char *) imagedata;
  919.     break;
  920.     
  921. /*********************************/
  922.     
  923.    case 4:   
  924.     theImage = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL, 
  925.                 width, height, 8, 0);
  926.     if (!theImage) FatalError("couldn't create theImage!");
  927.     bperline = theImage->bytes_per_line;
  928.     imagedata = (byte *) MyMalloc(bperline * height);            /* Try to allocate space for the actual X Image data */
  929.     if (imagedata == (byte*)NULL)
  930.     {
  931.       PrintDTDiagnostics("In CreateXImage, could not allocate enough image data.\n");
  932.       return(XImage*)NULL;
  933.     }
  934.     theImage->data = (char *) imagedata;
  935.     
  936.     if (ncols==0)
  937.     {                            /* ditherize */
  938.       byte *dith;
  939.       
  940.       dith = (byte *) MyMalloc(width*height);            /* Try to allocate space for the actual X Image data */
  941.       if (dith == (byte*)NULL)
  942.       {
  943.     PrintDTDiagnostics("In CreateXImage, could not allocate enough image data.\n");
  944.     return(XImage*)NULL;
  945.       }
  946.       if (theImage->bits_per_pixel == 4) {
  947.     for (i=0, pp=dith, lip=imagedata; i<height; i++, lip+=bperline)
  948.       for (j=0, ip=lip, half=0; j<width; j++,pp++,half++) {
  949.         if (half&1) { *ip = *ip + ((*pp&0x0f)<<4);  ip++; }
  950.         else *ip = *pp&0x0f;
  951.       }
  952.       }
  953.       else if (theImage->bits_per_pixel == 8)
  954.     memcpy(imagedata, dith, width*height);
  955.       
  956.       else FatalError("This display is too bizarre.  Can't create XImage.");
  957.       
  958.       free(dith);
  959.     }
  960.     
  961.     else {     /* don't ditherize */
  962.       if (theImage->bits_per_pixel == 4) {
  963.     for (i=0, pp=origData, lip=imagedata; i<height; i++, lip+=bperline) {
  964.       for (j=0, ip=lip, half=0; j<width; j++,pp++,half++) {
  965.         if (half&1) { *ip = *ip + ((cols[*pp]&0x0f)<<4);  ip++; }
  966.         else *ip = cols[*pp]&0x0f;
  967.       }
  968.     }
  969.       }
  970.       else if (theImage->bits_per_pixel == 8) {
  971.     for (i=width*height, pp=origData, ip=imagedata; i>0; i--,pp++,ip++) {
  972.       *ip = (byte) cols[*pp];
  973.     }
  974.       }
  975.       else FatalError("This display's too bizarre.  Can't create XImage.");
  976.     }
  977.     break;
  978.     
  979. /*********************************/
  980.     
  981.    case 6:
  982.     theImage = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL, 
  983.                 width, height, 8, 0);
  984.     if (!theImage) FatalError("couldn't create theImage!");
  985.     
  986.     if (theImage->bits_per_pixel != 8)
  987.       FatalError("This display's too bizarre.  Can't create XImage.");
  988.     
  989.     bperline = theImage->bytes_per_line;
  990.     imagedata = (byte *) MyMalloc(bperline * height);            /* Try to allocate space for the actual X Image data */
  991.     if (imagedata == (byte*)NULL)
  992.     {
  993.       PrintDTDiagnostics("In CreateXImage, could not allocate enough image data.\n");
  994.       return(XImage*)NULL;
  995.     }
  996.     theImage->data = (char *) imagedata;
  997.     
  998.     for (i=width*height, pp=origData, ip=imagedata; i>0; i--,pp++,ip++) {
  999.       *ip = (byte) cols[*pp];
  1000.     }
  1001.     break;
  1002.     
  1003. /*********************************/
  1004.     
  1005.    case 24:
  1006.    case 32:
  1007.     imagedata = (byte *) MyMalloc(4 * width * height);            /* Try to allocate space for the actual X Image data */
  1008.     if (imagedata == (byte*)NULL)
  1009.     {
  1010.       PrintDTDiagnostics("In CreateXImage, could not allocate enough image data.\n");
  1011.       return(XImage*)NULL;
  1012.     }
  1013.     theImage = XCreateImage(theDisp,theVisual,dispDEEP,ZPixmap,0,
  1014.                 (char *) imagedata, width, height, 32, 0);
  1015.     if (!theImage) FatalError("couldn't create theImage!");
  1016.     
  1017.     if (theImage->byte_order == MSBFirst) 
  1018.       for (i=width*height, pp=origData, ip=imagedata; i>0; i--,pp++) {
  1019.     *ip++ = 0;
  1020.     *ip++ = (cols[*pp]>>16) & 0xff;
  1021.     *ip++ = (cols[*pp]>>8) & 0xff;
  1022.     *ip++ =  cols[*pp] & 0xff;
  1023.       }
  1024.     else 
  1025.       for (i=width*height, pp=origData, ip=imagedata; i>0; i--,pp++) {
  1026.     *ip++ =  cols[*pp] & 0xff;
  1027.     *ip++ = (cols[*pp]>>8) & 0xff;
  1028.     *ip++ = (cols[*pp]>>16) & 0xff;
  1029.     *ip++ = 0;
  1030.       }
  1031.     break;
  1032.     
  1033.     /*********************************/
  1034.     
  1035.    default: 
  1036.     sprintf(str,"no code to handle this display type (%d bits deep)",
  1037.         dispDEEP);
  1038.     FatalError(str);
  1039.     break;
  1040.   }
  1041.   return(theImage);
  1042. }                                    /* end function CreateXImage */
  1043.  
  1044.  
  1045.  
  1046.  
  1047. /***********************************/
  1048. void FatalError (identifier)
  1049.      char *identifier;
  1050. {
  1051.   fprintf(stderr, "%s: %s\n",cmd, identifier);
  1052. }
  1053.  
  1054.